package com.quanxiaoha.weblog.web.utils;

import com.quanxiaoha.weblog.web.model.vo.ai.ArticleWithMetadataVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: 犬小哈
 * @url: www.quanxiaoha.com
 * @date: 2024-01-15
 * @description: 文章智能推荐工具类
 **/
@Component
@Slf4j
public class ArticleRecommendUtil {

    // 技术领域专业术语词典
    private static final Map<String, Set<String>> TECH_DOMAIN_KEYWORDS = new HashMap<>();

    static {
        // 数据库相关
        TECH_DOMAIN_KEYWORDS.put("数据库", new HashSet<>(Arrays.asList(
            "数据库", "database", "mysql", "sql", "postgresql", "oracle", "mongodb", "redis", "sqlite",
            "数据", "表", "查询", "索引", "事务", "存储", "备份", "优化", "性能", "连接池",
            "主键", "外键", "关联", "join", "select", "insert", "update", "delete", "crud",
            "关系型", "非关系型", "nosql", "acid", "数据结构", "数据模型", "ER图", "范式",
            "分库分表", "读写分离", "主从复制", "集群", "分片", "数据迁移", "数据同步"
        )));

        // 前端相关
        TECH_DOMAIN_KEYWORDS.put("前端", new HashSet<>(Arrays.asList(
            "前端", "vue", "react", "angular", "javascript", "js", "html", "css", "typescript",
            "组件", "路由", "状态管理", "webpack", "vite", "npm", "yarn", "ui", "界面", "交互",
            "响应式", "移动端", "pc端", "浏览器", "dom", "ajax", "fetch", "axios"
        )));

        // 后端相关
        TECH_DOMAIN_KEYWORDS.put("后端", new HashSet<>(Arrays.asList(
            "后端", "java", "spring", "springboot", "springcloud", "mybatis", "hibernate",
            "api", "接口", "服务", "微服务", "分布式", "集群", "负载均衡", "缓存", "消息队列",
            "框架", "架构", "设计模式", "restful", "http", "https", "json", "xml"
        )));

        // 运维相关
        TECH_DOMAIN_KEYWORDS.put("运维", new HashSet<>(Arrays.asList(
            "运维", "docker", "kubernetes", "linux", "nginx", "apache", "tomcat", "部署",
            "监控", "日志", "性能", "安全", "网络", "服务器", "云服务", "aws", "阿里云", "腾讯云"
        )));
    }

    /**
     * 基于增强算法推荐相关文章
     * @param userMessage 用户消息
     * @param articles 所有文章列表（包含元数据）
     * @param maxResults 最大返回结果数
     * @return 推荐文章列表（按相关度排序）
     */
    public List<ArticleRecommendResult> recommendArticles(String userMessage, List<ArticleWithMetadataVO> articles, int maxResults) {
        if (StringUtils.isBlank(userMessage) || articles == null || articles.isEmpty()) {
            return Collections.emptyList();
        }

        // 预处理用户消息
        String processedMessage = preprocessText(userMessage);
        Set<String> messageWords = extractWords(processedMessage);

        // 识别用户问题的技术领域
        String detectedDomain = detectTechDomain(processedMessage, messageWords);

        if (messageWords.isEmpty()) {
            // 如果没有有效关键词，不推荐任何文章
            log.info("用户消息无有效关键词，不推荐文章");
            return Collections.emptyList();
        }

        // 计算每篇文章的相关度得分
        List<ArticleRecommendResult> results = new ArrayList<>();

        for (ArticleWithMetadataVO article : articles) {
            double similarity = calculateEnhancedSimilarity(messageWords, article, detectedDomain);
            log.debug("文章[{}]相似度: {}, 检测领域: {}", article.getTitle(), similarity, detectedDomain);

            if (similarity > 0.05) { // 降低阈值，确保有文章被推荐
                String matchKeywords = findMatchKeywords(messageWords, article, detectedDomain);
                results.add(new ArticleRecommendResult(article, similarity, matchKeywords));
            }
        }

        log.info("用户消息: [{}], 检测领域: [{}], 候选文章数: {}", userMessage, detectedDomain, results.size());

        // 按相关度排序并返回前N个结果，没有合适的则不推荐
        return results.stream()
                .sorted((a, b) -> Double.compare(b.getSimilarity(), a.getSimilarity()))
                .limit(maxResults)
                .collect(Collectors.toList());
    }

    /**
     * 识别技术领域
     */
    private String detectTechDomain(String processedMessage, Set<String> messageWords) {
        Map<String, Integer> domainScores = new HashMap<>();

        for (Map.Entry<String, Set<String>> entry : TECH_DOMAIN_KEYWORDS.entrySet()) {
            String domain = entry.getKey();
            Set<String> keywords = entry.getValue();

            int score = 0;
            for (String keyword : keywords) {
                if (processedMessage.contains(keyword) || messageWords.contains(keyword)) {
                    score++;
                }
            }
            domainScores.put(domain, score);
        }

        // 返回得分最高的领域
        return domainScores.entrySet().stream()
                .max(Map.Entry.comparingByValue())
                .filter(entry -> entry.getValue() > 0)
                .map(Map.Entry::getKey)
                .orElse("通用");
    }

    /**
     * 计算增强的文章与用户消息的相似度
     */
    private double calculateEnhancedSimilarity(Set<String> messageWords, ArticleWithMetadataVO article, String detectedDomain) {
        if (messageWords.isEmpty()) {
            return 0.0;
        }

        // 1. 标题匹配得分 (权重: 30%)
        double titleScore = calculateTitleMatchScore(messageWords, article.getTitle());

        // 2. 内容匹配得分 (权重: 25%)
        double contentScore = calculateContentMatchScore(messageWords, article.getContent());

        // 3. 分类匹配得分 (权重: 20%)
        double categoryScore = calculateCategoryMatchScore(messageWords, article.getCategoryName(), detectedDomain);

        // 4. 标签匹配得分 (权重: 15%)
        double tagScore = calculateTagMatchScore(messageWords, article.getTagNames(), detectedDomain);

        // 5. 摘要匹配得分 (权重: 10%)
        double summaryScore = calculateSummaryMatchScore(messageWords, article.getSummary());

        // 6. 时效性权重
        double timeScore = calculateTimeScore(article.getCreateTime());

        // 7. 热度权重
        double popularityScore = calculatePopularityScore(article);

        // 综合评分：内容相关度(85%) + 时效性(10%) + 热度(5%)
        double totalContentScore = titleScore * 0.3 + contentScore * 0.25 + categoryScore * 0.2 + tagScore * 0.15 + summaryScore * 0.1;
        double finalScore = totalContentScore * 0.85 + timeScore * 0.1 + popularityScore * 0.05;

        // 如果没有任何内容匹配，返回0分，不推荐
        if (totalContentScore == 0.0) {
            finalScore = 0.0;
        }

        log.debug("文章[{}] - 标题:{}, 内容:{}, 分类:{}, 标签:{}, 摘要:{}, 最终:{}",
                article.getTitle(), titleScore, contentScore, categoryScore, tagScore, summaryScore, finalScore);

        return finalScore;
    }

    /**
     * 计算分类匹配得分
     */
    private double calculateCategoryMatchScore(Set<String> messageWords, String categoryName, String detectedDomain) {
        if (StringUtils.isBlank(categoryName)) {
            return 0.0;
        }

        String lowerCategoryName = categoryName.toLowerCase();

        // 直接匹配检测到的技术领域
        if (!detectedDomain.equals("通用") && lowerCategoryName.contains(detectedDomain.toLowerCase())) {
            return 1.0;
        }

        // 检查分类名称是否包含用户消息中的关键词
        Set<String> categoryWords = extractWords(lowerCategoryName);
        Set<String> intersection = new HashSet<>(messageWords);
        intersection.retainAll(categoryWords);

        if (intersection.isEmpty()) {
            // 检查是否有模糊匹配
            for (String messageWord : messageWords) {
                if (lowerCategoryName.contains(messageWord) || messageWord.contains(lowerCategoryName)) {
                    return 0.5; // 模糊匹配给一半分数
                }
            }
            return 0.0;
        }

        return Math.min(1.0, (double) intersection.size() / Math.max(messageWords.size(), categoryWords.size()) * 2);
    }

    /**
     * 计算标签匹配得分
     */
    private double calculateTagMatchScore(Set<String> messageWords, List<String> tagNames, String detectedDomain) {
        if (tagNames == null || tagNames.isEmpty()) {
            return 0.0;
        }

        double maxScore = 0.0;
        int matchedTags = 0;

        for (String tagName : tagNames) {
            if (StringUtils.isBlank(tagName)) {
                continue;
            }

            String lowerTagName = tagName.toLowerCase();

            // 检查是否匹配技术领域关键词
            if (!detectedDomain.equals("通用")) {
                Set<String> domainKeywords = TECH_DOMAIN_KEYWORDS.get(detectedDomain);
                if (domainKeywords != null && domainKeywords.contains(lowerTagName)) {
                    matchedTags++;
                    maxScore = Math.max(maxScore, 1.0);
                    continue;
                }
            }

            // 检查标签是否包含用户消息中的关键词
            Set<String> tagWords = extractWords(lowerTagName);
            Set<String> intersection = new HashSet<>(messageWords);
            intersection.retainAll(tagWords);

            if (!intersection.isEmpty()) {
                matchedTags++;
                double score = (double) intersection.size() / Math.max(messageWords.size(), tagWords.size());
                maxScore = Math.max(maxScore, score);
            }
        }

        // 如果有多个标签匹配，给予额外加分
        return matchedTags > 1 ? Math.min(1.0, maxScore * 1.2) : maxScore;
    }

    /**
     * 计算摘要匹配得分
     */
    private double calculateSummaryMatchScore(Set<String> messageWords, String summary) {
        if (StringUtils.isBlank(summary)) {
            return 0.0;
        }

        Set<String> summaryWords = extractWords(summary.toLowerCase());
        Set<String> intersection = new HashSet<>(messageWords);
        intersection.retainAll(summaryWords);

        return summaryWords.isEmpty() ? 0.0 : (double) intersection.size() / summaryWords.size();
    }

    /**
     * 计算内容匹配得分
     */
    private double calculateContentMatchScore(Set<String> messageWords, String content) {
        if (StringUtils.isBlank(content)) {
            return 0.0;
        }

        String lowerContent = content.toLowerCase();
        Set<String> contentWords = extractWords(lowerContent);
        Set<String> intersection = new HashSet<>(messageWords);
        intersection.retainAll(contentWords);

        if (intersection.isEmpty()) {
            // 检查是否有模糊匹配
            for (String messageWord : messageWords) {
                if (lowerContent.contains(messageWord)) {
                    return 0.2; // 模糊匹配给一些分数
                }
            }
            return 0.0;
        }

        // 内容匹配计算相对匹配度，避免长文本稀释匹配度
        double matchRatio = (double) intersection.size() / Math.min(messageWords.size(), 10); // 限制分母最大为10
        return Math.min(1.0, matchRatio);
    }

    /**
     * 计算标题匹配得分
     */
    private double calculateTitleMatchScore(Set<String> messageWords, String title) {
        if (StringUtils.isBlank(title)) {
            return 0.0;
        }

        String lowerTitle = title.toLowerCase();
        Set<String> titleWords = extractWords(lowerTitle);
        Set<String> intersection = new HashSet<>(messageWords);
        intersection.retainAll(titleWords);

        if (intersection.isEmpty()) {
            // 检查是否有模糊匹配
            for (String messageWord : messageWords) {
                if (lowerTitle.contains(messageWord) || messageWord.contains(lowerTitle)) {
                    return 0.3; // 模糊匹配给一些分数
                }
            }
            return 0.0;
        }

        // 标题匹配给予更高权重
        return Math.min(1.0, (double) intersection.size() / Math.max(messageWords.size(), titleWords.size()) * 1.5);
    }

    /**
     * 计算时效性得分
     */
    private double calculateTimeScore(LocalDateTime createTime) {
        if (createTime == null) {
            return 0.0;
        }
        
        long daysBetween = ChronoUnit.DAYS.between(createTime, LocalDateTime.now());
        
        // 30天内的文章得分较高，之后逐渐衰减
        if (daysBetween <= 30) {
            return 1.0;
        } else if (daysBetween <= 90) {
            return 0.8;
        } else if (daysBetween <= 180) {
            return 0.6;
        } else if (daysBetween <= 365) {
            return 0.4;
        } else {
            return 0.2;
        }
    }

    /**
     * 计算热度得分
     */
    private double calculatePopularityScore(ArticleWithMetadataVO article) {
        long readNum = article.getReadNum() != null ? article.getReadNum() : 0;

        // 简单的对数归一化
        if (readNum <= 0) {
            return 0.1;
        } else if (readNum <= 100) {
            return 0.3;
        } else if (readNum <= 500) {
            return 0.5;
        } else if (readNum <= 1000) {
            return 0.7;
        } else {
            return 0.9;
        }
    }

    /**
     * 查找匹配的关键词
     */
    private String findMatchKeywords(Set<String> messageWords, ArticleWithMetadataVO article, String detectedDomain) {
        Set<String> matchedWords = new HashSet<>();

        // 检查标题匹配
        if (StringUtils.isNotBlank(article.getTitle())) {
            Set<String> titleWords = extractWords(article.getTitle().toLowerCase());
            Set<String> titleMatches = new HashSet<>(messageWords);
            titleMatches.retainAll(titleWords);
            matchedWords.addAll(titleMatches);
        }

        // 检查分类匹配
        if (StringUtils.isNotBlank(article.getCategoryName())) {
            Set<String> categoryWords = extractWords(article.getCategoryName().toLowerCase());
            Set<String> categoryMatches = new HashSet<>(messageWords);
            categoryMatches.retainAll(categoryWords);
            matchedWords.addAll(categoryMatches);
        }

        // 检查标签匹配
        if (article.getTagNames() != null) {
            for (String tagName : article.getTagNames()) {
                if (StringUtils.isNotBlank(tagName)) {
                    Set<String> tagWords = extractWords(tagName.toLowerCase());
                    Set<String> tagMatches = new HashSet<>(messageWords);
                    tagMatches.retainAll(tagWords);
                    matchedWords.addAll(tagMatches);
                }
            }
        }

        // 如果检测到特定技术领域，优先显示领域名称
        if (!detectedDomain.equals("通用")) {
            return detectedDomain + "相关";
        }

        if (matchedWords.isEmpty()) {
            return "推荐阅读";
        }

        return String.join(", ", matchedWords.stream().limit(3).collect(Collectors.toList()));
    }

    /**
     * 文本预处理
     */
    private String preprocessText(String text) {
        if (StringUtils.isBlank(text)) {
            return "";
        }
        
        // 转小写，移除标点符号
        return text.toLowerCase()
                   .replaceAll("[\\p{Punct}\\s]+", " ")
                   .trim();
    }

    /**
     * 提取关键词
     */
    private Set<String> extractWords(String text) {
        if (StringUtils.isBlank(text)) {
            return Collections.emptySet();
        }
        
        // 停用词列表
        Set<String> stopWords = new HashSet<>(Arrays.asList(
            "的", "了", "在", "是", "我", "有", "和", "就", "不", "人", "都", "一", "一个", "上", "也", "很", "到", "说", "要", "去", "你", "会", "着", "没有", "看", "好", "自己", "这"
        ));
        
        return Arrays.stream(text.split("\\s+"))
                .filter(word -> word.length() > 1) // 过滤单字符
                .filter(word -> !stopWords.contains(word)) // 过滤停用词
                .collect(Collectors.toSet());
    }

    /**
     * 文章推荐结果
     */
    public static class ArticleRecommendResult {
        private final ArticleWithMetadataVO article;
        private final double similarity;
        private final String matchKeywords;

        public ArticleRecommendResult(ArticleWithMetadataVO article, double similarity, String matchKeywords) {
            this.article = article;
            this.similarity = similarity;
            this.matchKeywords = matchKeywords;
        }

        public ArticleWithMetadataVO getArticle() {
            return article;
        }

        public double getSimilarity() {
            return similarity;
        }

        public String getMatchKeywords() {
            return matchKeywords;
        }
    }
}
